﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ServiceStack.Redis;
using System.Net.Sockets;
using System.Threading;

namespace yq.CacheHelp.Redis
{
    internal partial class RedisClient<T>
    {

        //private IList<Action<IRedisClient>> list;

        
        
        //public void HSetTrans<F>(Func<IRedisClient, F> doWrite)
        //{
        //    list.Add(  ToAction(doWrite) );
        //}

        //public static Action<IRedisClient> ToAction<T>(Func<IRedisClient, T> fun)
        //{
        //    return t =>
        //    {
        //        fun(t);
        //    };
        //} 


        /// <summary>
        /// 读取
        /// </summary>
        /// <typeparam name="F"></typeparam>
        /// <param name="doRead"></param>
        /// <returns></returns>
        public F TryRedisRead<F>(Func<IRedisClient, F> doRead)
        {
            PooledRedisClientManager prcm = RedisManagers.GetClientManager(config);
            IRedisClient client = null;
            try
            {
                using (client = prcm.GetReadOnlyClient())
                {
                    return doRead(client);
                }
            }
            catch (RedisException ex)
            {
                FindReadException(prcm, ex, client.Host, client.Port);
               // throw new Exception("Redis读取异常Host:" + client.Host + ",Port:" + client.Port);
                return default(F);
            }
            finally
            {
                if (client != null)
                {
                    client.Dispose();
                }
            }
        }

        /// <summary>
        /// 写入
        /// </summary>
        /// <typeparam name="F"></typeparam>
        /// <param name="doWrite"></param>
        /// <returns></returns>
        public F TryRedisWrite<F>(Func<IRedisClient, F> doWrite)
        {
            PooledRedisClientManager prcm = RedisManagers.GetClientManager(config);
            IRedisClient client = null;
            try
            {
                using (client = prcm.GetClient())
                {
                    return doWrite(client);
                }
            }
            catch (RedisException)
            {
                throw new Exception("Redis写入异常.Host:" + client.Host + ",Port:" + client.Port);
            }
            finally
            {
                if (client != null)
                {
                    client.Dispose();
                }
            }
        }

     

        /// <summary>
        /// 处理只读服务失效
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="host"></param>
        /// <param name="port"></param>
        private static void FindReadException(PooledRedisClientManager prcm, RedisException ex, string host, int port)
        {
            ////如果请求处理的节点已经存在,则不需要再处理了
            if (RedisManagers.ExceptionReadLists.ContainsKey(host + ":" + port))
            {
                return;
            }
            RedisManagers.ExceptionReadLists.Add(host + ":" + port, "");

            //开始处理
            ServiceStack.Common.Web.EndPoint info = prcm.RemoveReadEndPoint(host, port);

            if (info != null)
            {
                TestEndPoint test = new TestEndPoint(info, prcm);
                Thread td = new Thread(test.Connect);
                td.Start();
            }
        }




    }

    public class TestEndPoint
    {

        public TestEndPoint(ServiceStack.Common.Web.EndPoint _info, PooledRedisClientManager _prcm)
        {
            info = _info;
            prcm = _prcm;
        }

        private ServiceStack.Common.Web.EndPoint info = null;
        private PooledRedisClientManager prcm = null;

        /// <summary>
        /// 检测失效连接是否还可用
        /// </summary>
        /// <param name="info"></param>
        public void Connect()
        {

            if (info == null)
            {
                return;
            }

            int sendTimeout = -1;
            bool isConnect = false;

            while (true)
            {
                using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                {
                    socket.SendTimeout = sendTimeout;

                    //请求连接
                    socket.Connect(info.Host, info.Port);
                    isConnect = socket.Connected;
                    socket.Close();
                }

                if (isConnect == false)
                {
                    Thread.Sleep(5000);
                }
                else
                {
                    //跳出循环
                    //如果在限制次数内连接重新可用
                    string key = info.Host + ":" + info.Port;

                
                    //重新写入到池中
                    prcm.AddReadEndPoint(info.Host, info.Port);

                    Console.WriteLine("成功将新节点写入到池中");

                    //从失效库中移除
                    if (RedisManagers.ExceptionReadLists.ContainsKey(key))
                    {
                        RedisManagers.ExceptionReadLists.Remove(key);
                    }

                    break;
                }
            }
        }



    }
}
